param([string]$op = 'apply', [string]$literalPath, [string]$webApplicationUrl, [string]$modOwner)

Add-PSSnapIn Microsoft.SharePoint.Powershell -ea SilentlyContinue

$nswcm = "urn:sharepointutil:webconfigmod";

function Apply-SPWebConfigModifications([string]$literalPath, [string]$webApplicationUrl, [string]$modOwner = $nswcm){

    $wa = Get-SPWebApplication $webApplicationUrl

    $xml = [xml](gc -literalpath $literalpath)
    $xns = new-object System.Xml.XmlNamespaceManager $xml.NameTable
    $xns.AddNamespace("wcm", $nswcm)
    $xml.SelectNodes("//*[@wcm:id or @wcm:type]", $xns) | %{
        $node = $_
        $ids= $_.GetAttribute("id", $nswcm);
        $type= $_.GetAttribute("type", $nswcm);
        if ([string]::isnullorempty($type)){
            $type = "EnsureChildNode"
        }
        $sType = [enum]::Parse([Microsoft.SharePoint.Administration.SPWebConfigModification+SPWebConfigModificationType], $type, $true)
        
        if ($type -ieq 'EnsureAttribute'){
            if ([string]::isnullorempty($ids)){
                write-host "id attribute must be specified for the EnsureAttribute mode"
                continue
            }
            $arid = $ids.Split(',') #multiple attributes per node might be assigned
        } else {
            $arid = $ids
        }
        
        $arid | %{
        
            $id = $_.Trim()

            $path = [string]::Join("/", ($node.SelectNodes("ancestor::*") | %{ $_.LocalName} ) )
            if ($type -ieq 'EnsureChildNode'){
                $name = '{0}[@{1}=''{2}'']' -f $node.LocalName, $id, $node.GetAttribute($id)                
                $clone = $node.Clone();
                $clone.RemoveAttribute("id", $nswcm)
                $clone.RemoveAttribute("type", $nswcm)
                $value = $clone.OuterXml
            } elseif ($type -ieq 'EnsureSection'){
                $name = $node.LocalName
                $value = '<{0}> </{0}>' -f $name
            } elseif ($type -ieq 'EnsureAttribute') {
                $path = [string]::Join("/", ($node.SelectNodes("ancestor-or-self::*") | %{ $_.LocalName} ) )
                $name = $id
                $value = $node.GetAttribute($id)
            }
            
            $mod = new-object Microsoft.SharePoint.Administration.SPWebConfigModification
            $mod.Name = $name
            $mod.Path = $path
            $mod.Owner = $modOwner
            $mod.Type = $sType
            $mod.Value = $value
            write-host "$sType under $path, xml: $value"
            $wa.WebConfigModifications.Add($mod)        
        }
    }

    $wa.Update();
    $wa.Parent.ApplyWebConfigModifications() 
}

function Clear-SPWebConfigModifications([string]$webApplicationUrl, [string]$modOwner = $nswcm){

    $wa = Get-SPWebApplication $webApplicationUrl
        if ($wa.WebConfigModifications -ne $null){
        ($wa.WebConfigModifications | ?{ $_.Owner -ieq $modOwner}).Clone() | %{ 
            $wa.WebConfigModifications.Remove($_) | out-null
            write-host $_.Type $_.Value
        }
        $wa.Update();
        $wa.Parent.ApplyWebConfigModifications() 
    }
}

#main
if ([string]::isnullorempty($modOwner)){
    $modOwner = $nswcm
}

if ([string]::isnullorempty($webApplicationUrl)){
    write-host -ForegroundColor red "-webApplicationUrl argument is required"
    exit 1
}

if ($op -ieq 'apply'){
    Apply-SPWebConfigModifications -literalPath $literalPath -webApplicationUrl $webApplicationUrl -modOwner $modOwner
} elseif ($op -ieq 'clear'){
    Clear-SPWebConfigModifications -webApplicationUrl $webApplicationUrl -modOwner $modOwner
} else
{
    write-host -ForegroundColor red "unrecognized parameter -op:  " + $op
    exit 1
}
